/**
 * 模拟方法实现运算符
 */

/**
 * 题1：实现 new 运算符 语法 new constructor[([arguments])]
 * new 运算符调用构造函数或者类创建对象时做了以下事情
 * 1) 创建一个空对象
 * 2) 给空对象添加 __proto__属性，链接到构造函数的原型对象
 * 3) 函数调用的 this 指向这个创建的新对象
 * 4) 如果这个构造函数不返回对象，则返回 this，也就是这个创建的新对象
 * @param {Function} constructor 构造函数 
 * @param {*} args 传入构造函数的参数
 */
export function myNew (constructor, ...args) {
  // 1.判断构造函数类型是否正确
  if (typeof constructor !== 'function') {
    throw new TypeError('The first param of new function must be a function')
  }
  // 2.以构造函数的原型创建一个新对象
  const obj = Object.create(constructor.prototype)
  // 3.调用构造函数，拿到返回的数据
  let res = constructor.call(obj, args)
  // 4.判断返回值是否为对象
  if (typeof res === 'object' || typeof res === 'function' || typeof res === null) {
    return res
  }
  return obj
}

/**
 * 题2：自定义方法实现 instanceof 检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
 * @param {Object} obj 
 * @param {Function} func 
 */
export const myInstanceof = (obj, func) => {
  // 1.基础数据类型直接 false
  const primaryDataType = (typeof obj !== 'object' && typeof obj !== 'function') || obj === null
  if (primaryDataType) {
    return false
  }
  // 获取对象的原型，并循环遍历他的原型链
  let proto = Object.getPrototypeOf(obj)
  while(true) {
    // 遍历到最后为 null 表示没找到
    if (proto === null) {
      return false
    }
    // 原型找到了返回 true
    if (proto === func.prototype) {
      return true
    }
    // 没找到继续往下找
    proto = Object.getPrototypeOf(proto)
  }
}